package com.aierkeji.call.cms.dao.jpa.custom.impl;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.NativeQuery;
import org.hibernate.transform.Transformers;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.CollectionUtils;

import com.aierkeji.call.cms.contants.Contants;
import com.aierkeji.call.cms.dao.jpa.custom.AkjCallClueDaoCustom;
import com.aierkeji.call.cms.entity.AkjCallClue;
import com.aierkeji.call.cms.entity.contants.CallResult;
import com.aierkeji.call.cms.entity.contants.CallStatus;
import com.aierkeji.call.cms.entity.contants.Gender;
import com.aierkeji.call.cms.entity.vo.AkjCallClueVo;
import com.aierkeji.call.cms.exception.BatchException;
import com.aierkeji.call.cms.util.AppConfig;
import com.aierkeji.call.cms.util.DateTimeUtils;
import com.aierkeji.call.cms.util.PageUtils;
import com.aierkeji.call.cms.util.StringUtils;

public class AkjCallClueDaoCustomImpl implements AkjCallClueDaoCustom {
	@PersistenceContext
	private EntityManager em;
	private final Logger log = LogManager.getLogger(getClass());

	@Autowired
	HibernateTemplate hibernateTemplate;

	@Autowired
	PlatformTransactionManager dataSourceTransactionManager;
	@Autowired
	TransactionDefinition transactionDefinition;

	@PersistenceUnit()
	private EntityManagerFactory entityManagerFactory;

	String listBase = null;

	@PostConstruct
	public void initPost() {
		StringBuffer sb = new StringBuffer();
		sb.append(
				"select clue.name,clue.gender,clue.phone,clue.assigned_at assignedAt,clue.created_at createdAt,clue.id");

		listBase = sb.toString();
	}

	@Override
//	@Transactional
	public int batchSave(List<AkjCallClue> list) throws BatchException {
		// TODO Auto-generated method stub
		if (CollectionUtils.isEmpty(list)) {
			return 0;
		}
		int size = list.size();
		int count = 0;
		int i2 = 0;
		int base = Integer.parseInt(AppConfig.getProperty("batch.save.count", "1000"));
		EntityManager em = entityManagerFactory.createEntityManager();
		EntityTransaction et = em.getTransaction();
		et.begin();
		for (int i = 0; i < size; i++) {
			try {

				em.persist(list.get(i));
				if ((i != 0 && (i + 1) % base == 0) || i == (size - 1)) { // 每1000条数据执行一次，或者最后不足1000条时执行
					et.commit();
				
					
					if (i == (size - 1)) {
						i2 = size - count * base;
					} else {
						et.begin();
						count++;
					}
				}
			} catch (Exception e) {
				// TODO: handle exception
				BatchException ex = new BatchException(e.getMessage(), e);

				ex.setSuccessCount(count * base + i2);
				et.rollback();
				log.error("", e);
				em.close();
				throw ex;
			}
		}
		em.close();
		return size;
	}

	public <T extends Enum> EnumType<T> generalHibernateEnum(Class<T> t) {
		Properties params = new Properties();
		params.put("enumClass", t.getName());
		params.put("useNamed", "true");
		EnumType<T> enumType = new EnumType<T>();
		enumType.setTypeConfiguration(new TypeConfiguration());
		enumType.setParameterValues(params);
		return enumType;
	}

	private Object[] getQuerySql(Map<String, Object> paramMap) {
		StringBuffer sb = new StringBuffer();
		sb.append("select clue.name,clue.gender,clue.phone,clue.assigned_at assignedAt,clue.created_at createdAt,");
		sb.append(" clue.id,clue.remark,clue.last_call_at lastCallAt,");
		sb.append(
				" clue.last_call_time lastCallTime,clue.last_call_status lastCallStatus,clue.last_call_result lastCallResult ,");
		sb.append(" cluegroup.group_name groupName,assignedUser.name assignedName,clue.last_remark lastRemark ");
		String hql = sb.toString()
				+ " from Akj_call_clue clue left join akj_call_clue_group cluegroup on clue.clue_group_id = cluegroup.id "
				+ " left join  akj_call_user assignedUser on clue.assigned_to = assignedUser.id where  1=1 ";
		String countsql = "select count(1) from  Akj_call_clue clue left join akj_call_clue_group cluegroup on clue.clue_group_id = cluegroup.id  left join  akj_call_user assignedUser on clue.assigned_to = assignedUser.id  where 1=1  ";
		String groupId = (String) paramMap.get("groupId");
		Long createdBy = (Long) paramMap.get("createdBy");
		String manager = (String)paramMap.get("manager");
		String name = (String) paramMap.get("name");
		String status = (String) paramMap.get("status");
		String endDate = (String) paramMap.get("endDate");
		String startDate = (String) paramMap.get("startDate");
		String assigneStartDate = (String) paramMap.get("assigneStartDate");
		String assigneEndDate = (String) paramMap.get("assigneEndDate");
		String assigneTo = (String) paramMap.get("assigneTo");
		String callStatus = (String) paramMap.get("callStatus");
		String callResult = (String) paramMap.get("callResult");
		String calledStatus = (String) paramMap.get("calledStatus");
		Boolean  groupDeleteFlag = (Boolean) paramMap.get("groupDeleteFlag");
		List<Object> paramList = new ArrayList<Object>();
		if(groupDeleteFlag!=null) {
		}else {
			hql += " and cluegroup.is_delete = ? ";
			countsql += " and cluegroup.is_delete =? ";
			paramList.add(false);
		}
		
		if (createdBy != null) {
			hql += " and clue.created_by =? ";
			countsql += " and clue.created_by =? ";
			paramList.add(createdBy);
		}
		
		if (!StringUtils.isEmpty(manager)) {
			hql += " and clue.created_by =? ";
			countsql += " and clue.created_by =? ";
			paramList.add(Long.parseLong(manager));
		}

		if (!StringUtils.isEmpty(groupId)) {
			hql += " and clue.clue_group_id =? ";
			countsql += " and clue.clue_group_id =? ";
			paramList.add(Long.parseLong(groupId));
		}
		if (!StringUtils.isEmpty(name)) {
			hql += " and (clue.name like ?  or clue.phone like ?) ";
			countsql += " and (clue.name like ?  or clue.phone like ?) ";
			paramList.add("%" + name + "%");
			paramList.add("%" + name + "%");
		}
		if (!StringUtils.isEmpty(status) && !"All".equals(status)) {
			if ("Y".equals(status)) {
				hql += " and (clue.assigned_at is not null) ";
				countsql += " and (clue.assigned_at is not null) ";
			} else if ("N".equals(status)) {
				hql += " and (clue.assigned_at is  null) ";
				countsql += " and (clue.assigned_at is  null) ";
			}
		}

		if (!StringUtils.isEmpty(assigneTo)) {
			hql += " and (assignedUser.id = ? ) ";
			countsql += " and (assignedUser.id = ? ) ";
			paramList.add(Long.parseLong(assigneTo));
		}
		if (!StringUtils.isEmpty(callStatus)) {
			if("Y".equals(callStatus)) {
				
				
				if("Y".equals(calledStatus)) {
					hql += " and (clue.last_call_status = ? ) ";
					countsql += " and (clue.last_call_status = ? ) ";
					paramList.add(CallStatus.CONNECT.name());
				}else if("N".equals(calledStatus)) {
					hql += " and (clue.last_call_status = ? ) ";
					countsql += " and (clue.last_call_status = ? ) ";
					paramList.add(CallStatus.UNCONNECT.name());

				}else {
					hql += " and (clue.last_call_status != ? and clue.last_call_status is not null ) ";
					countsql += " and (clue.last_call_status != ? and clue.last_call_status is not null ) ";
					paramList.add(CallStatus.NONE.name());

				}
			}else if("N".equals(callStatus)) {
				hql += " and (clue.last_call_status = ? ) ";
				countsql += " and (clue.last_call_status = ? ) ";
				paramList.add(CallStatus.NONE.name());
			}
			
		}
		if (!StringUtils.isEmpty(callResult)) {
			hql += " and (clue.last_call_result = ? ) ";
			countsql += " and (clue.last_call_result = ? ) ";
			paramList.add(callResult);
		}

		if (!StringUtils.isEmpty(endDate)) {
			endDate += " 23:59:59";
			Date date = DateTimeUtils.converStringToDate(endDate, DateTimeUtils.DATE_PATTERN_TIMESTAMP);

			hql += " and clue.created_at <= ? ";
			countsql += " and clue.created_at <= ? ";
			paramList.add(date);
		}

		if (!StringUtils.isEmpty(startDate)) {
			startDate += " 00:00:0";
			Date date = DateTimeUtils.converStringToDate(startDate, DateTimeUtils.DATE_PATTERN_TIMESTAMP);

			hql += " and clue.created_at >= ? ";
			countsql += " and clue.created_at >= ? ";
			paramList.add(date);
		}
		
		if (!StringUtils.isEmpty(assigneEndDate)) {
			assigneEndDate += " 23:59:59";
			Date date = DateTimeUtils.converStringToDate(assigneEndDate, DateTimeUtils.DATE_PATTERN_TIMESTAMP);

			hql += " and clue.assigned_at <= ? ";
			countsql += " and clue.assigned_at <= ? ";
			paramList.add(date);
		}

		if (!StringUtils.isEmpty(assigneStartDate)) {
			assigneStartDate += " 00:00:0";
			Date date = DateTimeUtils.converStringToDate(assigneStartDate, DateTimeUtils.DATE_PATTERN_TIMESTAMP);

			hql += " and clue.assigned_at >= ? ";
			countsql += " and clue.assigned_at >= ? ";
			paramList.add(date);
		}

		hql += " order by id desc";
		Object[] objs = {hql,countsql,paramList};
		return objs;
	}

	public Page<AkjCallClueVo> query(Integer pageNo, Map<String, Object> paramMap,int pageSize) {
		Object[] objs = getQuerySql(paramMap);
		Query query = this.em.createNativeQuery(objs[0].toString());
		NativeQuery nQuery = (NativeQuery) query;

		EnumType<Gender> gender = generalHibernateEnum(Gender.class);
		EnumType<CallStatus> callStatusEnum = generalHibernateEnum(CallStatus.class);
		EnumType<CallResult> callResultEnum = generalHibernateEnum(CallResult.class);

		nQuery.addScalar("gender", new CustomType(gender));
		nQuery.addScalar("name", StandardBasicTypes.STRING);
		nQuery.addScalar("id", StandardBasicTypes.LONG);
		nQuery.addScalar("phone", StandardBasicTypes.STRING);
		nQuery.addScalar("assignedAt", StandardBasicTypes.TIMESTAMP);
		nQuery.addScalar("createdAt", StandardBasicTypes.TIMESTAMP);
		nQuery.addScalar("remark", StandardBasicTypes.STRING);
		nQuery.addScalar("lastCallAt", StandardBasicTypes.TIMESTAMP);
		nQuery.addScalar("lastCallTime", StandardBasicTypes.LONG);
		nQuery.addScalar("lastCallStatus", new CustomType(callStatusEnum));
		nQuery.addScalar("lastCallResult", new CustomType(callResultEnum));
		nQuery.addScalar("groupName", StandardBasicTypes.STRING);
		nQuery.addScalar("assignedName", StandardBasicTypes.STRING);
		nQuery.addScalar("lastRemark", StandardBasicTypes.STRING);

		nQuery.setResultTransformer(Transformers.aliasToBean(AkjCallClueVo.class));
		Query cquery = em.createNativeQuery(objs[1].toString());
		List<Object> paramList = (List<Object>)objs[2];
		if (!CollectionUtils.isEmpty(paramList)) {
			for (int i = 0; i < paramList.size(); i++) {
				query.setParameter((i + 1), paramList.get(i));
				cquery.setParameter((i + 1), paramList.get(i));
			}
		}

		List<AkjCallClueVo> list = query.setFirstResult((pageNo - 1) * pageSize)
				.setMaxResults(pageSize).getResultList();
		BigInteger count = (BigInteger) cquery.getResultList().get(0);
//		count  = new BigInteger("30");
		PageRequest pageRequest = PageUtils.buildPageRequestNoSort(pageNo, pageSize);
		Page<AkjCallClueVo> page = new PageImpl<AkjCallClueVo>(list, pageRequest, count.intValue());
		return page;
	}

	@Override
	public int assigneUser(List<Long> list, Integer id,Long updatedBy) throws BatchException {
		// TODO Auto-generated method stub
		if (CollectionUtils.isEmpty(list)) {
			return 0;
		}
		int size = list.size();
		int count = 0;
		int i2 = 0;
		Date now = DateTimeUtils.getCurrentTime();
		int base = Integer.parseInt(AppConfig.getProperty("batch.save.count", "1000"));
//		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		EntityManager em = entityManagerFactory.createEntityManager();
		EntityTransaction et = em.getTransaction();
		try {
//			session = hibernateTemplate.getSessionFactory().openSession();
//			transaction = session.beginTransaction();
			String hql = "update Akj_call_clue set assigned_to = ?1 ,assigned_At = ?2,last_call_status=?4,updated_by=?5,updated_at=?2 where id = ?3";
			et.begin();
			Query nQuery = em.createNativeQuery(hql);
			for (int i = 0; i < size; i++) {
				nQuery.setParameter(1, id).setParameter(2, now).setParameter(3, list.get(i))
						.setParameter(4, CallStatus.NONE.name()).setParameter(5, updatedBy).executeUpdate();
				if ((i != 0 && (i + 1) % base == 0) || i == (size - 1)) { // 每1000条数据执行一次，或者最后不足1000条时执行
//					dataSourceTransactionManager.commit(transactionStatus);
					et.commit();
					if (i == (size - 1)) {
						i2 = size - count * base;
					} else {
						et.begin();
						count++;
					}
				}
			}

		} catch (Exception e) {
			// TODO: handle exception
			BatchException ex = new BatchException(e.getMessage(), e);
			ex.setSuccessCount(count * base + i2);
//			dataSourceTransactionManager.rollback(transactionStatus);
			et.rollback();
			log.error("", e);
			em.close();
			throw ex;
		}
		em.close();
		return size;
	}
}
